#include "../include/EventLoop.h"
#include "../include/Acceptor.h"
#include "../include/TcpConnection.h"
#include "../include/Mylogger.h"
#include <unistd.h>
#include <sys/eventfd.h>

EventLoop::EventLoop(Acceptor &acceptor)
: _epfd(createEpollFd())
, _isLooping(false)
, _acceptor(acceptor)
, _evtList(1024)
, _evtfd(createEventFd())
, _mutex()
{
    //监听listenfd，也就是socket创建文件描述符
    addEpollReadFd(_acceptor.fd());//
    //监听eventfd返回的文件描述符
    addEpollReadFd(_evtfd);//
}

EventLoop::~EventLoop()
{
    close(_epfd);
    close(_evtfd);
}

void EventLoop::loop()
{
    _isLooping = true;
    while(_isLooping)
    {
        waitEpollFd();
    }
}

void EventLoop::unloop()
{
    _isLooping = false;
}

void EventLoop::setConnectionCallback(TcpConnectionCallback &&cb)
{
    _onConnectionCb = std::move(cb);
}

void EventLoop::setMessageCallback(TcpConnectionCallback &&cb)
{
    _onMessageCb = std::move(cb);
}

void EventLoop::setCloseCallback(TcpConnectionCallback &&cb)
{
    _onCloseCb = std::move(cb);
}

void EventLoop::waitEpollFd()
{
    int nready;
    do 
    {
        nready = ::epoll_wait(_epfd, &*_evtList.begin(), _evtList.size(), 5000);
    }while(-1 == nready && errno == EINTR);

    if(-1 == nready)
    {
        LogError("%d{%Y-%m-%d %H:%M:%S} %c [%p] %c %x: %m%n","epoll_wait is error");
        return;
    }
    else if(0 == nready)
    {
        cout << ">>epoll_wait timeout" <<  endl;
        
    }
    else
    {
        //如果连接请求多了之后，需要让vector扩容
        if(nready == (int)_evtList.size())
        {
            _evtList.resize(2 * nready);
        }

        for(int idx = 0; idx < nready; ++idx)
        {
            int fd = _evtList[idx].data.fd;
            //新的连接
            if(fd == _acceptor.fd())//监听的文件描述符是不是listenfd
            {
                if(_evtList[idx].events & EPOLLIN)
                {
                    //处理新的连接
                    handleNewConnection();
                }
            }
            else if(fd == _evtfd)
            {
                if(_evtList[idx].events & EPOLLIN)
                {
                    handleRead();
                    //执行所有的回调函数
                    doPengdingFunctors();
                }

            }
            else
            {
                //老的连接
                if(_evtList[idx].events & EPOLLIN)
                {
                    //处理消息的发送
                    handleMessage(fd);
                }

            }
        }
    }

}
void EventLoop::handleNewConnection()
{
    //connfd如果有正确值的时候，就表明三次握手建立成功
    int connfd = _acceptor.accept();
    if(connfd < 0)
    {
        LogError("%d{%Y-%m-%d %H:%M:%S} %c [%p] %c %x: %m%n","handleNewConnection accept");
        return;
    }
    //将新的连接返回的文件描述符放在红黑树上进行监听
    addEpollReadFd(connfd);

    //就可以创建一条连接，也就是TCP连接
    TcpConnectionPtr con(new TcpConnection(connfd, this));

    //注册TCP网络编程过程中的三个事件
    con->setConnectionCallback(_onConnectionCb);//连接建立的事件
    con->setMessageCallback(_onMessageCb);//消息到达事件
    con->setCloseCallback(_onCloseCb);//连接断开的事件

    _conns.insert(std::make_pair(connfd, con));

    //连接已经建立了，所以需要在此处调用回调函数
    con->handleConnectionCallback();
}

void EventLoop::handleMessage(int fd)
{
    auto iter = _conns.find(fd);
    if(iter != _conns.end())
    {
        //在TcpConnection里面，写一个函数isClosed，
        //看看recv函数读数据的时候，返回值是不是
        //等于0
        bool flag = iter->second->isClosed();
        if(flag)
        {
            //1、连接关闭的事件
            //执行连接断开的事件
            iter->second->handleCloseCallback();
            //如果连接断开了，就需要将对应的文件描述符从
            //红黑树上摘除掉
            delEpollReadFd(fd);
            //也要将键值对connfd与TcpConnection从map中删除
            _conns.erase(iter);
        }
        else
        {
            //2、处理消息发送的事件
            iter->second->handleMessageCallback();
        }
    }
    else
    {
        LogError("%d{%Y-%m-%d %H:%M:%S} %c [%p] %c %x: %m%n","该链接不存在");
        return;
    }
}

int EventLoop::createEpollFd()
{
    int fd = ::epoll_create1(0);
    if(fd < 0)
    {
        LogError("%d{%Y-%m-%d %H:%M:%S} %c [%p] %c %x: %m%n","epoll_create1");
        return fd;
    }

    return fd;
}

void EventLoop::addEpollReadFd(int fd)
{
    struct epoll_event evt;
    evt.events = EPOLLIN;
    evt.data.fd = fd;

    int ret = ::epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &evt);
    if(ret < 0)
    {
        LogError("%d{%Y-%m-%d %H:%M:%S} %c [%p] %c %x: %m%n","epoll_ctl add");
        return;
    }
}

void EventLoop::delEpollReadFd(int fd)
{
    struct epoll_event evt;
    evt.events = EPOLLIN;
    evt.data.fd = fd;

    int ret = ::epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, &evt);
    if(ret < 0)
    {
        LogError("%d{%Y-%m-%d %H:%M:%S} %c [%p] %c %x: %m%n","epoll_ctl del");
        return;
    }
}

void EventLoop::handleRead()
{
    uint64_t one = 1;
    ssize_t ret = read(_evtfd, &one, sizeof(one));
    if(ret != sizeof(one))
    {
        LogError("%d{%Y-%m-%d %H:%M:%S} %c [%p] %c %x: %m%n","read");
        return;
    }
}

void EventLoop::wakeup()
{
    uint64_t one = 1;
    ssize_t ret = write(_evtfd, &one, sizeof(one));
    if(ret != sizeof(one))
    {
        LogError("%d{%Y-%m-%d %H:%M:%S} %c [%p] %c %x: %m%n","write");
        return;
    }

}
void EventLoop::doPengdingFunctors()
{
    /* Point &&rref = Point(1, 2); */
    /* rref; */
    //延长变量（对象）的生命周期,可以使用右值引用
    //缩短变量的生命周期，可以使用大括号的形式
    vector<Functor> tmp;
    {
        MutexLockGuard autoLock(_mutex);
        tmp.swap(_pendings);
    }

    for(auto &cb : tmp)
    {
        //执行回调函数，也就是使用TcpConnection中
        //的send发送msg
        //代码在TcpConnection中的sendInLoop函数中
        cb();
    }
}

void EventLoop::runInLoop(Functor &&cb)
{
    {
        //锁的粒度(其实就是锁的范围)
        //将所有的任务全部存储到vector中，以便以后执行
        MutexLockGuard autoLock(_mutex);
        _pendings.push_back(std::move(cb));
    }

    //唤醒操作
    wakeup();
}

int EventLoop::createEventFd()
{
    int fd = eventfd(10, 0);
    if(fd < 0)
    {
        LogError("%d{%Y-%m-%d %H:%M:%S} %c [%p] %c %x: %m%n","eventfd create is error");
        return fd;
    }

    return fd;
}
